package com.db.concurrency;

import static org.junit.Assert.assertTrue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;

/**
 * @author Alexander Kotov (kotov.alex.22@gmail.com)
 */
public abstract class ConcurrentHarness {

    protected static final int CYCLES = 500_000;
    protected ExecutorService executor;

    public ConcurrentHarness() {
        super();
    }

    @Before
    public void initExecutor() {
        executor = new ThreadPoolExecutor(32, 32, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(CYCLES));
    }

    protected void submitTasks() {
        for (int i = 0; i < CYCLES; i++) {
            executor.submit(newTask());
        }
    }

    @After
    public void collectResults() throws Exception {
        waitAllTasks();
        checkResults();
        cleanUp();
    }


    public void waitAllTasks() throws InterruptedException {
        executor.shutdown();
        boolean terminated = executor.awaitTermination(25, TimeUnit.SECONDS);
        assertTrue("Finished all tasks", terminated);
    }

    protected abstract void checkResults();

    protected abstract Runnable newTask();

    protected abstract void cleanUp() throws Exception;
}
